package org.lds.scheduled.job.admin.business.job.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.lds.scheduled.job.admin.business.job.converter.*;
import org.lds.scheduled.job.admin.business.job.entity.Job;
import org.lds.scheduled.job.admin.business.job.mapper.JobMapper;
import org.lds.scheduled.job.admin.business.job.model.request.*;
import org.lds.scheduled.job.admin.business.job.model.response.*;
import org.lds.scheduled.job.admin.business.job.service.JobBaseService;
import org.lds.scheduled.job.admin.starter.holder.JobHolder;
import org.lds.scheduled.job.common.model.dto.ResultDTO;
import org.lds.scheduled.job.common.model.db.OrderBy;
import org.lds.scheduled.job.common.model.db.PageResult;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 基础服务实现类
 *
 * @author lidongsheng
 * @since 2025-01-16
 */
@RequiredArgsConstructor
@Slf4j
@Service
public class JobBaseServiceImpl implements JobBaseService {
    private final JobMapper jobMapper;
    private final JobBaseCreateRequestToEntityConverter jobBaseCreateRequestToEntityConverter;
    private final JobBaseUpdateRequestToEntityConverter jobBaseUpdateRequestToEntityConverter;
    private final JobBaseListRequestToEntityConverter jobBaseListRequestToEntityConverter;
    private final JobToBaseResponseConverter jobToBaseResponseConverter;
    private final JobBaseListPageRequestToEntityConverter jobBaseListPageRequestToEntityConverter;
    private final JobBaseGetByKeyRequestToEntityConverter jobBaseGetByKeyRequestToEntityConverter;
    private final JobHolder jobHolder;

    @Override
    @Transactional
    public ResultDTO<JobBaseResponse> createJob(JobBaseCreateRequest request) {
        try {
            Job job = jobBaseCreateRequestToEntityConverter.convert(request);
            int rowCount = jobMapper.insert(job);
            JobBaseResponse response = jobToBaseResponseConverter.convert(job);

            if (rowCount == 1) {
                jobHolder.save(job.getId(), job.getAppId());
            }
            return ResultDTO.success(response);
        } catch (DuplicateKeyException e) {
            return ResultDTO.fail("DATA_REPEAT", "数据重复");
        }
    }

    @Transactional
    @Override
    public ResultDTO<JobBaseBatchCreateResponse> batchCreateJob(JobBaseBatchCreateRequest request) {
        JobBaseBatchCreateResponse response = JobBaseBatchCreateResponse.builder()
                .responses(request.getRequests().stream().map(this::createJob).collect(Collectors.toList()))
                .build();
        return ResultDTO.success(response);
    }

    @Transactional
    @Override
    public ResultDTO<JobBaseDeleteResponse> deleteJob(JobBaseDeleteRequest request) {
        int rowCount = jobMapper.deleteById(request.getId());

        JobBaseDeleteResponse response = JobBaseDeleteResponse.builder()
                .request(request)
                .build();
        if (rowCount == 1) {
            jobHolder.remove(request.getId());
        }
        return ResultDTO.success(response);
    }

    @Transactional
    @Override
    public ResultDTO<JobBaseBatchDeleteResponse> batchDeleteJob(JobBaseBatchDeleteRequest request) {
        JobBaseBatchDeleteResponse response = JobBaseBatchDeleteResponse.builder()
                .responses(request.getRequests().stream().map(this::deleteJob).collect(Collectors.toList()))
                .build();
        return ResultDTO.success(response);
    }

    @Transactional
    @Override
    public ResultDTO<JobBaseResponse> updateJob(JobBaseUpdateRequest request) {
        Job job = jobBaseUpdateRequestToEntityConverter.convert(request);
        JobBaseResponse response = jobToBaseResponseConverter.convert(job);

        Job currJob = jobMapper.selectById(request.getId());
        if (currJob == null) return ResultDTO.success(response);

        try {
            int rowCount = jobMapper.updateById(job);

            if (rowCount == 1) {
                if (BooleanUtils.isFalse(request.getEnable()) || (Objects.isNull(request.getEnable()) && BooleanUtils.isFalse(currJob.getEnable()))) {
                    jobHolder.remove(request.getId());
                } else {
                    jobHolder.save(job.getId(),
                            Objects.isNull(job.getAppId()) ? currJob.getAppId() : job.getAppId());
                }
            }
            return ResultDTO.success(response);
        } catch (DuplicateKeyException e) {
            return ResultDTO.fail("DATA_REPEAT", "数据重复");
        }
    }

    @Transactional
    @Override
    public ResultDTO<JobBaseBatchUpdateResponse> batchUpdateJob(JobBaseBatchUpdateRequest request) {
        JobBaseBatchUpdateResponse response = JobBaseBatchUpdateResponse.builder()
                .requests(request.getRequests().stream().map(this::updateJob).collect(Collectors.toList()))
                .build();
        return ResultDTO.success(response);
    }

    @Override
    public ResultDTO<JobBaseResponse> getJobById(JobBaseGetByIdRequest request) {
        Job job = jobMapper.selectById(request.getId());
        if (job == null) {
            return ResultDTO.success();
        }

        JobBaseResponse response = jobToBaseResponseConverter.convert(job);
        return ResultDTO.success(response);
    }

    @Override
    public ResultDTO<JobBaseListResponse> getJobByIds(JobBaseGetByIdsRequest request) {
        List<Job> list = request.getIds().stream().map(id -> jobMapper.selectById(id)).collect(Collectors.toList());
        return ResultDTO.success(JobBaseListResponse.builder()
                .jobs(list.stream().map(job -> jobToBaseResponseConverter.convert(job)).collect(Collectors.toList()))
                .build());
    }

    @Override
    public Job getJobByKey(JobBaseGetByKeyRequest request) {
        return jobMapper.selectOne(new QueryWrapper<>(jobBaseGetByKeyRequestToEntityConverter.convert(request)));
    }

    @Override
    public ResultDTO<JobBaseListResponse> listJob(JobBaseListRequest request) {
        QueryWrapper<Job> wrapper = new QueryWrapper<>(jobBaseListRequestToEntityConverter.convert(request));
        if (StringUtils.isNotEmpty(request.getOrderByKey())) {
            wrapper.orderByDesc(request.getOrderByKey());
        }

        List<Job> jobs = jobMapper.selectList(wrapper);

        JobBaseListResponse response = JobBaseListResponse.builder()
                .jobs(jobs.stream().map(jobToBaseResponseConverter::convert).collect(Collectors.toList()))
                .build();
        return ResultDTO.success(response);
    }

    @Override
    public ResultDTO<JobBaseListResponse> listAllJob(OrderBy orderBy) {
        JobBaseListRequest jobRequest = JobBaseListRequest.builder().build();
        jobRequest.setOrderByKey(orderBy.getOrderByKey());
        return listJob(jobRequest);
    }

    @Override
    public ResultDTO<PageResult<JobBaseResponse>> listJobPage(JobBaseListPageRequest request) {
        Page<Job> page = new Page<>(request.getPageNum(), request.getPageSize(), true);

        QueryWrapper<Job> wrapper = new QueryWrapper<>(jobBaseListPageRequestToEntityConverter.convert(request));
        if (Objects.nonNull(request.getGtId())) {
            wrapper.gt("id", request.getGtId());
        }

        if (StringUtils.isNotEmpty(request.getOrderByKey())) {
            if (request.getOrderByDesc() != null && request.getOrderByDesc().booleanValue() == false) {
                wrapper.orderByAsc(request.getOrderByKey());
            } else {
                wrapper.orderByDesc(request.getOrderByKey());
            }
        }

        IPage<Job> pageResult = jobMapper.selectPage(page, wrapper);

        PageResult<JobBaseResponse> response = new PageResult(
                pageResult.getTotal(), pageResult.getPages(), pageResult.getCurrent(), pageResult.getSize(),
                pageResult.getRecords().stream().map(jobToBaseResponseConverter::convert).collect(Collectors.toList()));
        return ResultDTO.success(response);
    }

    @Override
    public ResultDTO<JobBaseBatchCreateResponse> batchCreateJobAsync(JobBaseBatchCreateRequest request) {
        JobBaseBatchCreateResponse response = JobBaseBatchCreateResponse.builder()
                .responses(request.getRequests().parallelStream().map(this::createJob).collect(Collectors.toList()))
                .build();
        return ResultDTO.success(response);
    }

    @Override
    public ResultDTO<JobBaseBatchDeleteResponse> batchDeleteJobAsync(JobBaseBatchDeleteRequest request) {
        JobBaseBatchDeleteResponse response = JobBaseBatchDeleteResponse.builder()
                .responses(request.getRequests().parallelStream().map(this::deleteJob).collect(Collectors.toList()))
                .build();
        return ResultDTO.success(response);
    }

    @Override
    public ResultDTO<JobBaseBatchUpdateResponse> batchUpdateJobAsync(JobBaseBatchUpdateRequest request) {
        JobBaseBatchUpdateResponse response = JobBaseBatchUpdateResponse.builder()
                .requests(request.getRequests().parallelStream().map(this::updateJob).collect(Collectors.toList()))
                .build();
        return ResultDTO.success(response);
    }

}
